﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using System.Drawing;
using System.Windows.Forms;
using Styx;
using Styx.Combat.CombatRoutine;
using Styx.Helpers;
using Styx.Logic;
using Styx.Logic.Combat;
using Styx.Logic.Pathing;
using Styx.WoWInternals;
using Styx.WoWInternals.WoWObjects;
using Styx.Logic.POI;
using Styx.Logic.Inventory;

namespace HarmoniousVigor
{
    public abstract class CharacterClass
    {
        public virtual LocalPlayer characterPlayer { get { return HarmoniousVigor.Me; } }
        public virtual int level { get { return characterPlayer.Level; } }
        public virtual int meleeRange { get { return 5; } }
        public virtual int rangedRange { get { return 40; } }
        public virtual double targetRange { get { return characterPlayer.CurrentTarget.Distance2D; } }
        public virtual double healCheckRange { get { return 60; } }
        public int currentTalents;
        public bool talentsWrong = false;
        public virtual void printCharacterInfo()
        {
            Utils.Log(string.Format("You are a level {0} {1} {2}", level, getCurrentSpec(), characterPlayer.Class.ToString()));
            Utils.Log(string.Format("Your primary specialization is {0}", getPrimarySpec()));
            Utils.Log(string.Format("Your secondary specialization is {0}", getSecondarySpec()));
        }
        public virtual string getCurrentSpec()
        {
            int x = Lua.GetReturnVal<int>("return GetPrimaryTalentTree()", 0);
            return findSpec(x);
        }
        public virtual string getPrimarySpec()
        {
            int x = Lua.GetReturnVal<int>("return GetPrimaryTalentTree(false,false,1)", 0);
            return findSpec(x);
        }
        public virtual string getSecondarySpec()
        {
            int x = Lua.GetReturnVal<int>("return GetPrimaryTalentTree(false,false,2)", 0);
            return findSpec(x);
        }
        public virtual void meleeMovement()
        {      
            if (characterPlayer.CurrentTarget != null && Styx.BotManager.Current.Name != "Lazyraider")
            {
                if (targetRange <= meleeRange && characterPlayer.CurrentTarget.InLineOfSpellSight && (characterPlayer.IsBehind(characterPlayer.CurrentTarget) || characterPlayer.CurrentTarget.Aggro || Battlegrounds.IsInsideBattleground))
                {
                    if (characterPlayer.IsMoving)
                    {
                        Navigator.PlayerMover.MoveStop();
                        StyxWoW.SleepForLagDuration();
                    }
                }
                else
                {   /*
                    WoWPoint location = WoWMathHelper.CalculatePointFrom(characterPlayer.Location, characterPlayer.CurrentTarget.Location, meleeRange);
                    if (!characterPlayer.IsCasting)
                        Navigator.MoveTo(location);
                    */
                    
                    WoWPoint location = WoWMathHelper.CalculatePointBehind(characterPlayer.CurrentTarget.Location, characterPlayer.CurrentTarget.Rotation, 0);
                    if (!characterPlayer.IsCasting)
                        Navigator.MoveTo(location);   
                }
            }
        }
        public virtual void rangedMovement()
        {
            if (characterPlayer.CurrentTarget != null && Styx.BotManager.Current.Name != "Lazyraider")
            {
                if (targetRange <= rangedRange && characterPlayer.CurrentTarget.InLineOfSpellSight)
                {
                    if (characterPlayer.IsMoving)
                    {
                        Navigator.PlayerMover.MoveStop();
                        StyxWoW.SleepForLagDuration();
                    }
                }
                else
                {   /*
                    WoWPoint location = WoWMathHelper.CalculatePointFrom(characterPlayer.Location, characterPlayer.CurrentTarget.Location, meleeRange);
                    if (!characterPlayer.IsCasting)
                        Navigator.MoveTo(location);
                    */

                    WoWPoint location = WoWMathHelper.CalculatePointBehind(characterPlayer.CurrentTarget.Location, characterPlayer.CurrentTarget.Rotation, 0);
                    if (!characterPlayer.IsCasting)
                        Navigator.MoveTo(location);
                }
            }
        }
        public abstract bool Combat();
        public abstract bool PullSpell();
        public virtual bool Pull()
        {
            if (PullSpell())
                return true;
            else if (Combat())
                return true;
            else
                return false;
        }
        public abstract string findSpec(int i);
        public abstract bool Buff();
        public abstract bool Heal();
        public virtual void Pulse()
        {
            if (talentsWrong)
                changeTalents();
            if (Rest())
                return;
            if (Heal())
                return;
            if (Buff())
                return;
        }
        public virtual bool NeedRest
        {
            get
            {
                if (characterPlayer.Combat || !characterPlayer.IsAlive || characterPlayer.IsFlying || characterPlayer.IsSwimming || (characterPlayer.IsCasting && characterPlayer.CastingSpell.ToString().Equals("Cannibalize", StringComparison.OrdinalIgnoreCase)))
                    return false;

                if (characterPlayer.Race == WoWRace.Undead && (characterPlayer.HealthPercent < 70 || ((characterPlayer.PowerType == WoWPowerType.Mana || characterPlayer.Class == WoWClass.Druid) && characterPlayer.ManaPercent < 70))
                && ObjectManager.GetObjectsOfType<WoWUnit>(true, false).Where(u => u.Dead && (u.CreatureType == WoWCreatureType.Humanoid || u.CreatureType == WoWCreatureType.Undead) && u.Distance2D < 5).FirstOrDefault() != null)
                    return true;

                bool eatOrDrink = false;

                if (characterPlayer.HealthPercent < 70 && Consumable.GetBestFood(false) != null)
                    eatOrDrink = true;

                if ((characterPlayer.PowerType == WoWPowerType.Mana || characterPlayer.Class == WoWClass.Druid) && characterPlayer.ManaPercent < 70 && Consumable.GetBestDrink(false) != null)
                    eatOrDrink =  true;

                if (eatOrDrink)
                    return true;

                if ((characterPlayer.HasAura("Drink") && (StyxWoW.Me.PowerType == WoWPowerType.Mana || StyxWoW.Me.Class == WoWClass.Druid) && characterPlayer.ManaPercent < 100)
                   || (characterPlayer.HasAura("Food") && characterPlayer.HealthPercent < 100))
                    return true;

                return false;
            }
        }
        public virtual bool Rest()
        {
            if (characterPlayer.Combat || !characterPlayer.IsAlive || characterPlayer.IsSwimming || characterPlayer.IsFlying || (characterPlayer.IsCasting && characterPlayer.CastingSpell.ToString().Equals("Cannibalize", StringComparison.OrdinalIgnoreCase)))
                return false;

            if (characterPlayer.Race == WoWRace.Undead && (characterPlayer.HealthPercent < 70 || ((characterPlayer.PowerType == WoWPowerType.Mana || characterPlayer.Class == WoWClass.Druid) && characterPlayer.ManaPercent < 70)) 
                && ObjectManager.GetObjectsOfType<WoWUnit>(true, false).Where(u=> u.Dead && (u.CreatureType == WoWCreatureType.Humanoid || u.CreatureType == WoWCreatureType.Undead) && u.Distance2D < 5).FirstOrDefault() != null)
            {
                if (characterPlayer.IsMoving)
                {
                    Navigator.PlayerMover.MoveStop();
                    StyxWoW.SleepForLagDuration();
                }
                if (characterPlayer.Mounted)
                {
                    Styx.Logic.Mount.Dismount();
                    StyxWoW.SleepForLagDuration();
                }
                Utils.CastMe("Cannibalize");
                return true;
            }

            bool eatOrDrink = false;

            if (characterPlayer.HealthPercent < 70 && Consumable.GetBestFood(false) != null)
            {
                if (characterPlayer.IsMoving)
                {
                    Navigator.PlayerMover.MoveStop();
                    StyxWoW.SleepForLagDuration();
                }
                if (characterPlayer.Mounted)
                {
                    Styx.Logic.Mount.Dismount();
                    StyxWoW.SleepForLagDuration();
                }
                Styx.Logic.Common.Rest.FeedImmediate();
                eatOrDrink = true;
            }

            if ((characterPlayer.PowerType == WoWPowerType.Mana || characterPlayer.Class == WoWClass.Druid) && characterPlayer.ManaPercent < 70 && Consumable.GetBestDrink(false) != null)
            {
                if (characterPlayer.IsMoving)
                {
                    Navigator.PlayerMover.MoveStop();
                    StyxWoW.SleepForLagDuration();
                }
                if (characterPlayer.Mounted)
                {
                    Styx.Logic.Mount.Dismount();
                    StyxWoW.SleepForLagDuration();
                }
                Styx.Logic.Common.Rest.DrinkImmediate();
                eatOrDrink = true;
            }

            if (eatOrDrink)
                return true;

            if ((characterPlayer.HasAura("Drink") && (StyxWoW.Me.PowerType == WoWPowerType.Mana || StyxWoW.Me.Class == WoWClass.Druid) && characterPlayer.ManaPercent < 100)
               || (characterPlayer.HasAura("Food") && characterPlayer.HealthPercent < 100))
                return true;

            return false;
        }
        public virtual void Initialize()
        {
            updateCurrentTalents();
            checkGlyphs();
            checkTalents();
            Lua.Events.AttachEvent("ZONE_CHANGED", ZONE_CHANGED);
            Lua.Events.AttachEvent("ZONE_CHANGED_INDOORS", ZONE_CHANGED);
            Lua.Events.AttachEvent("ZONE_CHANGED_NEW_AREA", ZONE_CHANGED);
            Lua.Events.AttachEvent("EQUIPMENT_SWAP_FINISHED", EQUIPMENT_SWAP_FINISHED);
            Lua.Events.AttachEvent("ACTIVE_TALENT_GROUP_CHANGED", ACTIVE_TALENT_GROUP_CHANGED);
        }
        public abstract void checkGlyphs();
        public abstract void checkTalents();
        public abstract void talentsChanged();
        public virtual List<String> getGlyph(int slot)
        {
            return Lua.GetReturnValues("enabled, glyphType, glyphTooltipIndex, glyphSpellID, icon = GetGlyphSocketInfo("+slot+");return glyphSpellID;");
        }
        public virtual List<String> getTalent(int index, int talent)
        {
            return Lua.GetReturnValues("nameTalent, icon, tier, column, currRank, maxRank=GetTalentInfo(" + index + "," + talent + ");return nameTalent, currRank;");
        }
        public virtual void changeTalents()
        {
            if (characterPlayer.Combat || characterPlayer.IsSwimming || characterPlayer.IsFlying)
                return;
            if (characterPlayer.IsMoving)
            {
                Navigator.PlayerMover.MoveStop();
                StyxWoW.SleepForLagDuration();
            }
            if (characterPlayer.Mounted)
            {
                Styx.Logic.Mount.Dismount();
                StyxWoW.SleepForLagDuration();
            }
            Utils.Log("Attempting talent change");
            if (currentTalents == 1)
            { 
                Lua.DoString("SetActiveTalentGroup(2)");
                Thread.Sleep(500);
                while (characterPlayer.IsCasting) { }
            }
            else
            {
                Lua.DoString("SetActiveTalentGroup(1)");
                Thread.Sleep(500);
                while (characterPlayer.IsCasting) { }
            }
            
        }
        public virtual void updateCurrentTalents()
        {
            currentTalents=Lua.GetReturnVal<int>("activeVal = GetActiveTalentGroup();return activeVal;", 0);
        }
        public virtual void ZONE_CHANGED(object sender, LuaEventArgs args)
        {
            if (!talentsWrong)
            {
                Utils.Log("Changing zones. Checking talents.");
                if (StyxWoW.Me.IsInInstance && currentTalents == 2)
                {
                    talentsWrong = true;
                    Utils.Log("Changing to other spec for Dungeons");
                }
                else if (Battlegrounds.IsInsideBattleground && currentTalents == 2)
                {
                    talentsWrong = true;
                    Utils.Log("Changing to other spec for Battlegrounds");
                }
                else if (currentTalents == 2)
                {
                    talentsWrong = true;
                    Utils.Log("Changing to other spec for Leveling");
                }
                else
                    Utils.Log("No changes needed");
            }
        }
        public virtual void ACTIVE_TALENT_GROUP_CHANGED(object sender, LuaEventArgs args)
        {
            talentsWrong = false;
            Utils.Log("Talents updated");
            updateCurrentTalents();
            Utils.Log("Changing gear");
            if (currentTalents == 1)
                Lua.DoString("UseEquipmentSet(\"Test\")");
            else if(currentTalents == 2)
                Lua.DoString("UseEquipmentSet(\"Ret Leveling\")");
            talentsChanged();
            checkGlyphs();
            checkTalents();
        }
        public virtual void EQUIPMENT_SWAP_FINISHED(object sender, LuaEventArgs args)
        {
            Utils.Log("Gear swapped");
        }
        public void AutoAttack()
        {
            if (!characterPlayer.IsAutoAttacking)
            {
                Lua.DoString("StartAttack()");
            }
        }
        public void faceTarget()
        {
            if (!characterPlayer.IsFacing(characterPlayer.CurrentTarget.Location))
                characterPlayer.CurrentTarget.Face();
        }
        
    }
}
